﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Xml;
using SocialFront.Entities;
using SocialFront.Providers.Blog;
using SocialFront.Providers.Document;
using SocialFront.Providers.Image;
using SocialFront.Providers.Member;
using SocialFront.Providers.Relationship;
using SocialFront.Providers.User;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.relation;
using umbraco.cms.businesslogic.web;
using umbraco.DataLayer;
using umbraco.presentation.nodeFactory;
using Relation=umbraco.cms.businesslogic.relation.Relation;
using RelationApi = umbraco.cms.businesslogic.relation;

namespace SocialFront.Provider.Umbraco
{
    public class UmbracoRelationship : RelationshipBase
    {
        /// <summary>
        /// Gets the friends of member.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns></returns>
        public override IList<Member> GetFriendsOfMember(int memberId)
        {
            return GetTypedParents<Member>(GetRelations(memberId, "relateMemberToMemberFriend"));
        }

        /// <summary>
        /// Creates the friends of member.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns></returns>
        public override void CreateFriendsOfMember(int memberId)
        {
            //DeleteRelations(MemberProvider.Provider.GetCurrentMember().Id, "relateMemberToMemberFan");
            CreateRelationship(memberId, MemberProvider.Provider.GetCurrentMember().Id, "relateMemberToMemberFriend");

            // TODO: Should another relationship be made that works the other way? Or is this a dual-type relationship?
        }

        /// <summary>
        /// Determines whether [is member friend] [the specified member id].
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns>
        /// 	<c>true</c> if [is member friend] [the specified member id]; otherwise, <c>false</c>.
        /// </returns>
        public override bool IsMemberFriend(int memberId)
        {
            bool isFriend = false;
            IList<Member> members = GetFriendsOfMember(memberId);
            foreach (Member member in members)
            {
                if(member.Id == memberId)
                    isFriend = true;
            }
            return isFriend;
        }

        /// <summary>
        /// Gets the fans of member.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns></returns>
        public override IList<Member> GetFansOfMember(int memberId)
        {
            return GetTypedParents<Member>(GetRelations(memberId, "relateMemberToMemberFan"));
        }

        /// <summary>
        /// Creates the fans of member.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        public override void CreateFansOfMember(int memberId)
        {
            CreateRelationship(memberId, MemberProvider.Provider.GetCurrentMember().Id, "relateMemberToMemberFan");
        }

        /// <summary>
        /// Determines whether [is member fan] [the specified member id].
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns>
        /// 	<c>true</c> if [is member fan] [the specified member id]; otherwise, <c>false</c>.
        /// </returns>
        public override bool IsMemberFan(int memberId)
        {
            bool isFan = false;
            IList<Member> members = GetFansOfMember(memberId);
            foreach (Member member in members)
            {
                if (member.Id == memberId)
                    isFan = true;
            }
            return isFan;
        }

        /// <summary>
        /// Creates the fans or friend.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        public override void CreateFansOrFriend(int memberId)
        {
            if (MemberProvider.Provider.GetCurrentMember() != null)
            {
                if (memberId != MemberProvider.Provider.GetCurrentMember().Id)
                {
                    bool isMemberFan = RelationshipProvider.Provider.IsMemberFan(MemberProvider.Provider.GetCurrentMember().Id);
                    bool isMemberFriend = RelationshipProvider.Provider.IsMemberFriend(MemberProvider.Provider.GetCurrentMember().Id);
                    if (isMemberFan || isMemberFriend)
                    {
                        if (isMemberFan)
                            CreateFriendsOfMember(memberId);
                    }
                    else
                        CreateFansOfMember(memberId);
                }
            }
        }

        /// <summary>
        /// Gets the members I like by blog.
        /// </summary>
        /// <param name="blogId">The blog id.</param>
        /// <returns></returns>
        public override IList<Member> GetMembersILikeByBlog(int blogId)
        {
            return GetTypedParents<Member>(GetRelations(blogId, "relateMemberILikeBlog"));
        }

        /// <summary>
        /// Creates the member I like A blog.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <param name="blogId">The blog id.</param>
        /// <returns></returns>
        public override bool CreateMemberILikeABlog(int memberId, int blogId)
        {
            return CreateRelationship(memberId, blogId, "relateMemberILikeBlog");
        }

        /// <summary>
        /// Gets the members I like by blog.
        /// </summary>
        /// <param name="blog">The blog.</param>
        /// <returns></returns>
        public override IList<Member> GetMembersILikeByBlog(Blog blog)
        {
            return GetMembersILikeByBlog(blog.Id);
        }

        /// <summary>
        /// Creates the member I like A image.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <param name="imageId">The image id.</param>
        /// <returns></returns>
        public override bool CreateMemberILikeAImage(int memberId, int imageId)
        {
            return CreateRelationship(memberId, imageId, "relateMemberILikeImage");
        }

        /// <summary>
        /// Gets the members I like by image.
        /// </summary>
        /// <param name="blogId">The blog id.</param>
        /// <returns></returns>
        public override IList<Member> GetMembersILikeByImage(int imageId)
        {
            return GetTypedParents<Member>(GetRelations(imageId, "relateMemberILikeImage"));
        }

        /// <summary>
        /// Gets the members I like by image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <returns></returns>
        public override IList<Member> GetMembersILikeByImage(Image image)
        {
            return GetMembersILikeByImage(image.Id);
        }

        /// <summary>
        /// Gets the blogs I like by member.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns></returns>
        public override IList<Blog> GetBlogsILikeByMember(int memberId)
        {
            return GetTypedChildren<Blog>(GetRelations(memberId, "relateMemberILikeBlog"));
        }

        /// <summary>
        /// Gets the blogs I like by member.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        public override IList<Blog> GetBlogsILikeByMember(Member member)
        {
            return GetBlogsILikeByMember(member.Id);
        }

        /// <summary>
        /// Gets the images I like by member.
        /// </summary>
        /// <param name="memberId">The member id.</param>
        /// <returns></returns>
        public override IList<Image> GetImagesILikeByMember(int memberId)
        {
            return GetTypedChildren<Image>(GetRelations(memberId, "relateMemberILikeImage"));
        }

        /// <summary>
        /// Gets the member related to node.
        /// </summary>
        /// <returns></returns>
        /// 
        public override IList<Member> GetMemberRelatedToParentOfCurrentNode()
        {
            return GetTypedParents<Member>(GetRelations(Node.GetCurrent().Parent.Id, "relateMemberToMemberDocType"));
        }

        /// <summary>
        /// Checks if a relationship of the specified type exists between the parent and child objects
        /// </summary>
        /// <param name="parentId">The parent id.</param>
        /// <param name="childId">The child id.</param>
        /// <param name="relationAlias">The relation alias.</param>
        /// <returns></returns>
        public override bool RelationshipExists(int parentId, int childId, string relationAlias)
        {
            return Relation.IsRelated(parentId, childId, RelationType.GetByAlias(relationAlias));
        }


        /// <summary>
        /// Gets the images I like by member.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns></returns>
        public override IList<Image> GetImagesILikeByMember(Member member)
        {
            return GetTypedChildren<Image>(GetRelations(member.Id, "relateMemberILikeImage"));
        }

        /// <summary>
        /// Gets the member related to node.
        /// </summary>
        /// <returns></returns>
        public override IList<Member> GetMemberRelatedToCurrentNode()
        {
            return GetTypedParents<Member>(GetRelations(Node.GetCurrent().Id, "relateMemberToMemberDocType"));
        }

        /// <summary>
        /// Creates the relationship.
        /// </summary>
        /// <param name="parentId">The parent id.</param>
        /// <param name="childId">The child id.</param>
        /// <param name="relationshipType">Type of the relationship.</param>
        /// <returns></returns>
        private bool CreateRelationship(int parentId, int childId, string relationshipType)
        {
            RelationApi.Relation.MakeNew(parentId, childId, RelationApi.RelationType.GetByAlias(relationshipType),
                                         "Link " + parentId + " to " + childId + " type:" + relationshipType);
            return true;
        }

        private void DeleteRelations(int id, string relationshipType)
        {
            Relation[] relations = Relation.GetRelations(id, RelationType.GetByAlias(relationshipType));
            foreach (Relation relation in relations)
            {
                relation.Delete();
            }
        }

        /// <summary>
        /// Gets the relations.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="relationType">Type of the relation.</param>
        /// <returns></returns>
        private RelationApi.Relation[] GetRelations(int id, string relationType)
        {
            return RelationApi.Relation.GetRelations(id, RelationType.GetByAlias(relationType));
        }

        /// <summary>
        /// Gets the typed children.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="relations">The relations.</param>
        /// <returns></returns>
        private IList<T> GetTypedChildren<T>(RelationApi.Relation[] relations)
        {
            if (relations.Length == 0)
                return new List<T>();

            IList<T> list = new List<T>();
            if (typeof (T) == typeof (Blog))
            {
                foreach (RelationApi.Relation relation in relations)
                {
                    list.Add((T) (Object) BlogProvider.Provider.GetBlogById(relation.Child.Id));
                }
            }
            else if (typeof (T) == typeof (Image))
            {
                foreach (RelationApi.Relation relation in relations)
                {
                    list.Add((T) (Object) ImageProvider.Provider.GetImageById(relation.Child.Id));
                }
            }
            else if (typeof (T) == typeof (Member))
            {
                foreach (RelationApi.Relation relation in relations)
                {
                    list.Add((T) (Object) MemberProvider.Provider.GetMemberById(relation.Child.Id));
                }
            }
            return list;
        }

        /// <summary>
        /// Gets the typed parents.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <param name="relations">The relations.</param>
        /// <returns></returns>
        private IList<T> GetTypedParents<T>(RelationApi.Relation[] relations)
        {
            if (relations.Length == 0)
                return new List<T>();

            IList<T> list = new List<T>();
            if (typeof(T) == typeof(Blog))
            {
                foreach (RelationApi.Relation relation in relations)
                {
                    list.Add((T)(Object)BlogProvider.Provider.GetBlogById(relation.Parent.Id));
                }
            }
            else if (typeof(T) == typeof(Image))
            {
                foreach (RelationApi.Relation relation in relations)
                {
                    list.Add((T)(Object)ImageProvider.Provider.GetImageById(relation.Parent.Id));
                }
            }
            else if (typeof(T) == typeof(Member))
            {
                foreach (RelationApi.Relation relation in relations)
                {
                    list.Add((T)(Object)MemberProvider.Provider.GetMemberById(relation.Parent.Id));
                }
            }
            return list;
        }
    }
}